package com.black.utils.office.word;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.black.utils.office.excel.ExcelEntity;
import com.black.utils.office.excel.ExcelHeader;
import lombok.Getter;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Word导出工具类
 * 支持多级标题和表格插入
 */
public class WordExportUtil {

    /**
     * Word文档对象
     */
    @Getter
    private final XWPFDocument document;

    /**
     * 标题样式映射
     */
    private final Map<Integer, XWPFParagraph> titleStyles;

    public WordExportUtil() {
        this.document = new XWPFDocument();
        this.titleStyles = new HashMap<>();
        initDefaultStyles();
    }

    /**
     * 初始化默认样式
     */
    private void initDefaultStyles() {
        // 一级标题样式
        XWPFParagraph title1 = document.createParagraph();
        title1.setStyle("Heading1");
        XWPFRun run1 = title1.createRun();
        run1.setFontSize(24);
        run1.setBold(true);
        run1.setFontFamily("宋体");

        // 二级标题样式
        XWPFParagraph title2 = document.createParagraph();
        title2.setStyle("Heading2");
        XWPFRun run2 = title2.createRun();
        run2.setFontSize(20);
        run2.setBold(true);
        run2.setFontFamily("宋体");

        // 三级标题样式
        XWPFParagraph title3 = document.createParagraph();
        title3.setStyle("Heading3");
        XWPFRun run3 = title3.createRun();
        run3.setFontSize(16);
        run3.setBold(true);
        run3.setFontFamily("宋体");

        // 普通正文样式
        XWPFParagraph normal = document.createParagraph();
        XWPFRun normalRun = normal.createRun();
        normalRun.setFontSize(12);
        normalRun.setFontFamily("宋体");

        titleStyles.put(1, title1);
        titleStyles.put(2, title2);
        titleStyles.put(3, title3);
        titleStyles.put(0, normal);
    }

    /**
     * 添加一级标题
     *
     * @param text 标题文本
     */
    public void addTitle1(String text) {
        addTitle(text, 1);
    }

    /**
     * 添加二级标题
     *
     * @param text 标题文本
     */
    public void addTitle2(String text) {
        addTitle(text, 2);
    }

    /**
     * 添加三级标题
     *
     * @param text 标题文本
     */
    public void addTitle3(String text) {
        addTitle(text, 3);
    }

    /**
     * 添加指定级别的标题
     *
     * @param text  标题文本
     * @param level 标题级别
     */
    public void addTitle(String text, int level) {
        XWPFParagraph paragraph = document.createParagraph();
        if (level >= 1 && level <= 3) {
            paragraph.setStyle("Heading" + level);
            setOutlineLevel(paragraph, level - 1);
        }

        XWPFRun run = paragraph.createRun();
        run.setText(text);

        // 设置样式
        switch (level) {
            case 1:
                run.setFontSize(24);
                run.setBold(true);
                break;
            case 2:
                run.setFontSize(20);
                run.setBold(true);
                break;
            case 3:
                run.setFontSize(16);
                run.setBold(true);
                break;
            default:
                run.setFontSize(12);
                run.setBold(false);
        }
        run.setFontFamily("宋体");
    }

    /**
     * 设置段落的大纲级别（使标题在导航栏中可见）
     *
     * @param paragraph 段落
     * @param level     大纲级别（0-8，对应1-9级标题）
     */
    public static void setOutlineLevel(XWPFParagraph paragraph, int level) {
        // 确保级别在有效范围内
        int outlineLevel = Math.max(0, Math.min(8, level));

        CTPPr ppr = paragraph.getCTP().getPPr();
        if (ppr==null) {
            ppr = paragraph.getCTP().addNewPPr();
        }

        CTDecimalNumber outlineLvl = ppr.isSetOutlineLvl() ? ppr.getOutlineLvl():ppr.addNewOutlineLvl();
        outlineLvl.setVal(BigInteger.valueOf(outlineLevel));
    }

    /**
     * 添加段落文本
     *
     * @param text 文本内容
     */
    public void addParagraph(String text) {
        XWPFParagraph paragraph = document.createParagraph();
        XWPFRun run = paragraph.createRun();
        run.setText(text);
        run.setFontSize(12);
        run.setFontFamily("宋体");
    }

    /**
     * 插入表格（基于ExcelEntity）
     *
     * @param excelEntity Excel实体对象
     */
    public void addTable(ExcelEntity excelEntity) {
        List<ExcelHeader> headers = excelEntity.getHeaders();
        if (headers==null || headers.isEmpty()) {
            return;
        }

        // 创建表格
        XWPFTable table = document.createTable();

        // 设置表格属性
        table.setWidth("100%");
        table.setTableAlignment(TableRowAlign.CENTER);

        // 设置表格边框
        setTableBorders(table);

        // 处理表头
        processTableHeader(table, headers);

        // 处理数据行
        processTableData(table, excelEntity);
    }

    /**
     * 设置表格边框
     *
     * @param table 表格对象
     */
    private void setTableBorders(XWPFTable table) {
        // 设置表格边框样式
        CTTblBorders borders = CTTblBorders.Factory.newInstance();

        // 设置上下左右边框
        borders.setTop(createBorder("single", 4, "000000"));
        borders.setBottom(createBorder("single", 4, "000000"));
        borders.setLeft(createBorder("single", 4, "000000"));
        borders.setRight(createBorder("single", 4, "000000"));
        borders.setInsideH(createBorder("single", 4, "000000"));
        borders.setInsideV(createBorder("single", 4, "000000"));

        CTTblPr tblPr = table.getCTTbl().getTblPr();
        if (tblPr==null) {
            tblPr = table.getCTTbl().addNewTblPr();
        }
        tblPr.setTblBorders(borders);
    }

    /**
     * 创建边框
     *
     * @param type  边框类型
     * @param size  边框大小
     * @param color 边框颜色
     * @return CTBorder对象
     */
    private CTBorder createBorder(String type, int size, String color) {
        CTBorder border = CTBorder.Factory.newInstance();
        border.setVal(STBorder.Enum.forString(type));
        border.setSz(BigInteger.valueOf(size));
        border.setColor(color);
        return border;
    }

    /**
     * 处理表格表头
     *
     * @param table   表格对象
     * @param headers 表头列表
     */
    private void processTableHeader(XWPFTable table, List<ExcelHeader> headers) {
        // 创建表头行
        XWPFTableRow headerRow = table.getRow(0);
        if (headerRow==null) {
            headerRow = table.createRow();
        } else {
            // 清空现有单元格
            for (int i = headerRow.getTableCells().size() - 1; i >= 0; i--) {
                headerRow.removeCell(i);
            }
        }

        int total = headers.stream().mapToInt(ExcelHeader::getColumnWidth).sum();

        // 添加表头单元格
        for (ExcelHeader header : headers) {
            XWPFTableCell cell = headerRow.addNewTableCell();
            cell.setText(header.getName());

            cell.setWidth((double) header.getColumnWidth() * 100 / total + "%");
            // 设置表头样式
            setCellBackgroundColor(cell, "D3D3D3"); // 灰色背景

            // 设置字体加粗
            for (XWPFParagraph p : cell.getParagraphs()) {
                for (XWPFRun r : p.getRuns()) {
                    r.setBold(true);
                }
            }
        }
    }

    /**
     * 设置单元格背景颜色
     *
     * @param cell  单元格
     * @param color 颜色值
     */
    private void setCellBackgroundColor(XWPFTableCell cell, String color) {
        CTTcPr tcPr = cell.getCTTc().addNewTcPr();
        CTShd shd = tcPr.addNewShd();
        shd.setColor("auto");
        shd.setFill(color);
    }

    /**
     * 处理表格数据
     *
     * @param table       表格对象
     * @param excelEntity Excel实体对象
     */
    private void processTableData(XWPFTable table, ExcelEntity excelEntity) {
        JSONArray data = excelEntity.getData();
        if (data==null || data.isEmpty()) {
            return;
        }

        List<ExcelHeader> headers = excelEntity.getHeaders();

        // 处理数据行
        for (int i = 0; i < data.size(); i++) {
            JSONObject rowData = data.getJSONObject(i);
            XWPFTableRow dataRow = table.createRow();

            // 填充每列数据
            for (int j = 0; j < headers.size(); j++) {
                ExcelHeader header = headers.get(j);
                XWPFTableCell cell = dataRow.getCell(j);
                if (cell==null) {
                    cell = dataRow.addNewTableCell();
                }

                // 获取对应字段的值
                Object value = rowData.get(header.getKey());
                cell.setText(value!=null ? value.toString():"");
            }
        }

        // 处理合并单元格
        List<int[]> mergeCells = excelEntity.getMergeCells();
        if (mergeCells!=null && !mergeCells.isEmpty()) {
            processMergeCells(table, mergeCells);
        }
    }

    /**
     * 处理合并单元格
     *
     * @param table      表格对象
     * @param mergeCells 合并单元格信息
     */
    private void processMergeCells(XWPFTable table, List<int[]> mergeCells) {
        for (int[] mergeCell : mergeCells) {
            if (mergeCell.length==4) {
                int firstRow = mergeCell[0];
                int firstCol = mergeCell[1];
                int lastRow = mergeCell[2];
                int lastCol = mergeCell[3];

                // 在Word中合并单元格
                mergeTableCells(table, firstRow, firstCol, lastRow, lastCol);
            }
        }
    }

    /**
     * 合并表格单元格
     *
     * @param table    表格对象
     * @param firstRow 起始行索引
     * @param firstCol 起始列索引
     * @param lastRow  结束行索引
     * @param lastCol  结束列索引
     */
    private void mergeTableCells(XWPFTable table, int firstRow, int firstCol, int lastRow, int lastCol) {
        try {
            // 确保行和列存在
            for (int i = firstRow; i <= lastRow; i++) {
                while (table.getRows().size() <= i) {
                    table.createRow();
                }
                XWPFTableRow row = table.getRow(i);
                while (row.getTableCells().size() <= lastCol) {
                    row.addNewTableCell();
                }
            }

            // 合并水平单元格
            if (firstRow==lastRow && firstCol!=lastCol) {
                // 水平合并
                XWPFTableCell firstCell = table.getRow(firstRow).getCell(firstCol);
                firstCell.getCTTc().addNewTcPr().addNewHMerge().setVal(
                        STMerge.RESTART);

                // 设置被合并的单元格
                for (int j = firstCol + 1; j <= lastCol; j++) {
                    XWPFTableCell cell = table.getRow(firstRow).getCell(j);
                    if (cell!=null) {
                        cell.getCTTc().addNewTcPr().addNewHMerge().setVal(
                                STMerge.CONTINUE);
                    }
                }
            }
            // 合并垂直单元格
            else if (firstCol==lastCol && firstRow!=lastRow) {
                // 垂直合并
                XWPFTableCell firstCell = table.getRow(firstRow).getCell(firstCol);
                firstCell.getCTTc().addNewTcPr().addNewVMerge().setVal(
                        STMerge.RESTART);

                // 设置被合并的单元格
                for (int i = firstRow + 1; i <= lastRow; i++) {
                    XWPFTableCell cell = table.getRow(i).getCell(firstCol);
                    if (cell!=null) {
                        cell.getCTTc().addNewTcPr().addNewVMerge().setVal(
                                STMerge.CONTINUE);
                    }
                }
            }
            // 合并矩形单元格区域
            else if (firstRow!=lastRow && firstCol!=lastCol) {
                // 左上角单元格
                XWPFTableCell firstCell = table.getRow(firstRow).getCell(firstCol);
                firstCell.getCTTc().addNewTcPr().addNewHMerge().setVal(
                        STMerge.RESTART);
                firstCell.getCTTc().addNewTcPr().addNewVMerge().setVal(
                        STMerge.RESTART);

                // 第一行的其他单元格
                for (int j = firstCol + 1; j <= lastCol; j++) {
                    XWPFTableCell cell = table.getRow(firstRow).getCell(j);
                    if (cell!=null) {
                        cell.getCTTc().addNewTcPr().addNewHMerge().setVal(
                                STMerge.CONTINUE);
                        cell.getCTTc().addNewTcPr().addNewVMerge().setVal(
                                STMerge.CONTINUE);
                    }
                }

                // 其他行的所有单元格
                for (int i = firstRow + 1; i <= lastRow; i++) {
                    for (int j = firstCol; j <= lastCol; j++) {
                        XWPFTableCell cell = table.getRow(i).getCell(j);
                        if (cell!=null) {
                            cell.getCTTc().addNewTcPr().addNewHMerge().setVal(
                                    STMerge.CONTINUE);
                            cell.getCTTc().addNewTcPr().addNewVMerge().setVal(
                                    STMerge.CONTINUE);
                        }
                    }
                }
            }
        } catch (Exception e) {
            // 忽略合并单元格时的异常
        }
    }

    /**
     * 通过WordEntity导出Word文档
     *
     * @param entity Word导出实体
     */
    public void export(WordEntity entity) {
        // 设置文档标题
        if (entity.getDocumentTitle()!=null && !entity.getDocumentTitle().isEmpty()) {
            addTitle1(entity.getDocumentTitle());
        }

        // 处理章节
        for (WordEntity.Section section : entity.getSections()) {
            processSection(section, 0);
        }
    }

    /**
     * 处理章节（递归处理）
     *
     * @param section     章节对象
     * @param indentLevel 缩进级别
     */
    private void processSection(WordEntity.Section section, int indentLevel) {
        // 添加章节标题
        addTitle(section.getTitle(), section.getLevel());

        // 处理章节内容
        for (WordEntity.Content content : section.getContents()) {
            switch (content.getType()) {
                case PARAGRAPH:
                    // 添加段落
                    addParagraph((String) content.getData());
                    break;
                case TABLE:
                    // 添加表格
                    addTable((ExcelEntity) content.getData());
                    break;
                case SECTION:
                    // 递归处理子章节
                    processSection((WordEntity.Section) content.getData(), indentLevel + 1);
                    break;
            }
        }
    }

    /**
     * 导出Word文档到文件
     *
     * @param filePath 文件路径
     * @throws IOException IO异常
     */
    public void exportToFile(String filePath) throws IOException {
        try (FileOutputStream out = new FileOutputStream(filePath)) {
            document.write(out);
        }
    }

    /**
     * 导出Word文档到输出流
     *
     * @param outputStream 输出流
     * @throws IOException IO异常
     */
    public void exportToStream(OutputStream outputStream) throws IOException {
        document.write(outputStream);
    }
}